home *** CD-ROM | disk | FTP | other *** search
/ The Best of MacTutor - S…e Code for Volumes 1 to 5 / The Best of MacTutor - Source Code for Volume 1-5 (Wayzata Technology)(6031)(1990).bin / Source Code / #41 (Feb 89) / window source / Window 1Source < prev    next >
Text File  |  1988-12-16  |  32KB  |  1,175 lines

  1.  
  2.  
  3.  
  4.  
  5.  
  6. (*
  7.  
  8. © 1988, Apple Computer, Inc.
  9. All rights reserved.
  10.  
  11. Window1.p:  A HyperCard XCMD in MPW Pascal 2.0.2 
  12.            by Joe Zuffoletto
  13.            Version 1.0, 29 June 1988
  14.  
  15. Form:      Window title,top,left,bottom,right
  16.  
  17. Example:   window "My Window",50,100,300,400
  18.  
  19. Notes:     Window puts up a standard document window with
  20.            scroll bars. The window can be dragged, resized,
  21.            zoomed, and closed.
  22.  
  23.            Command-W is supported for closing the window.
  24.            Command-spacebar toggles the menubar on and off,
  25.            as in HyperCard. If you try to draw the window's 
  26.            title bar off the screen or under the menubar, 
  27.            Window will abort with an error message. Error 
  28.            messages can be examined by looking at 
  29.            HyperCard's global variable "the result" after 
  30.            calling Window.
  31.  
  32.            Window is MultiFinder friendly and works with 
  33.            HyperCard 1.2 or later. It supports multiple 
  34.            displays on the Mac II as well. 
  35.  
  36.            You must supply your own code for displaying 
  37.            whatever you want to display in the window.
  38.  
  39. ------------------------------------------------------------
  40.  
  41. To compile and link this file using MPW Pascal 2.0.2, select the following lines and press ENTER:
  42.  
  43. Pascal Window1.p
  44. link   -o "Hard Disk":HyperCard:"HyperCard Stacks":Home ∂
  45.        -rt XCMD=2000 -sn Main=Window ∂
  46.        Window1.p.o {MPW}Libraries:Interface.o ∂
  47.        {MPW}PLibraries:PasLib.o ∂
  48.        -m ENTRYPOINT
  49.  
  50. Use other link files as necessary.
  51.  
  52. The above link directives install the XCMD resource into the Home stack. You can substitute the name of any stack you want; be sure to provide the correct pathname. Also, make sure the target stack already has a resource fork or it won't work. You can create an empty resource fork in a stack
  53. with ResEdit.
  54.  
  55. ------------------------------------------------------------
  56.  
  57. *)
  58.  
  59. {$R-}
  60.  
  61. {$S Window}
  62.  
  63. UNIT DummyUnit;
  64.  
  65. INTERFACE
  66.  
  67. USES
  68.   MemTypes,QuickDraw,OSIntf,ToolIntf,PasLibIntf,HyperXCmd;
  69.  
  70. PROCEDURE EntryPoint(paramPtr:XCmdPtr);
  71.  
  72. IMPLEMENTATION
  73.  
  74. TYPE Str31 = String[31];
  75.  
  76.      OffScrHandle = ^OffScrRecPtr;    
  77.        {Attach to refCon of a window}
  78.      OffScrRecPtr = ^OffScrRecord;
  79.      OffScrRecord = RECORD
  80.                       {Next month!}
  81.                     END;
  82.  
  83.      ScrollHandle = ^ScrollPtr;
  84.        {Attach to refCon of a control}
  85.      ScrollPtr = ^ScrollRecord;
  86.      ScrollRecord = RECORD
  87.                       {Next month!}
  88.                     END;
  89.  
  90. PROCEDURE Window(paramPtr:XCmdPtr);FORWARD;
  91.  
  92.  
  93. PROCEDURE EntryPoint(paramPtr:XCmdPtr);
  94. BEGIN
  95.   Window(paramPtr);
  96. END;
  97.  
  98.  
  99. FUNCTION Min(int1,int2:INTEGER): INTEGER;
  100.  
  101. BEGIN
  102.   {Next month!}
  103. END; {Min}
  104.  
  105.  
  106. PROCEDURE InitBlit(theWindow:WindowPtr);
  107.  
  108. BEGIN
  109.   {Next month!}
  110. END; {InitBlit}
  111.  
  112.  
  113. PROCEDURE InvalContents(theWindow:WindowPtr;
  114.                         theOldSize:Rect);
  115.  
  116. BEGIN
  117.   {More to come next month!}
  118.   EraseRect(theWindow^.portRect);
  119.   InvalRect(theWindow^.portRect);
  120. END; {InvalContents}
  121.  
  122.  
  123. PROCEDURE DrawContents(theWindow:WindowPtr);
  124.  
  125. BEGIN
  126.   {Next month!}
  127. END; {DrawContents}
  128.  
  129.  
  130. PROCEDURE ScrollContents(theWindow:WindowPtr;dh,dv:INTEGER);
  131.  
  132. BEGIN
  133.   {Next month!}
  134. END; {ScrollContents}
  135.  
  136.  
  137. PROCEDURE MyScroll(theControl:ControlHandle;partCode:INTEGER);
  138.  
  139. BEGIN
  140.   {Next month!}
  141. END; {MyScroll}
  142.  
  143.  
  144. PROCEDURE Window(paramPtr:XCmdPtr);
  145.  
  146. CONST
  147.   minParamCount     =  5;
  148.   smallestHeight    =  100;
  149.   smallestWidth     =  100;
  150.   _WaitNextEvent    =  $A860;
  151.   _Unimplemented    =  $A89F;
  152.   active            =  0;
  153.   inactive          =  255;
  154.   MouseMovedEvt     =  $FA;
  155.   SuspendResumeEvt  =  $01;
  156.   SuspendEventMask  =  $1;
  157.   ConvertScrapMask  =  $2;
  158.   browseTool        =  6069;
  159.   HCWidth           =  512;
  160.   HCHeight          =  342;
  161.   padding           =  16;
  162.  
  163. VAR
  164.   toolVis,patVis:              BOOLEAN;
  165.   msgVis,fatVis:               BOOLEAN;
  166.   hasWaitNextEvent:            BOOLEAN;
  167.   inBackGround,smallScreen:    BOOLEAN;
  168.   DoneFlag,HaveEvent:          BOOLEAN;
  169.   wTop,wLeft,wBottom,wRight:   INTEGER;
  170.   partCode,controlCode:        INTEGER;
  171.   largestHeight,largestWidth:  INTEGER;
  172.   dummy,charCode:              INTEGER;
  173.   screenWidth,screenHeight:    INTEGER;
  174.   myDocWidth,myDocHeight:      INTEGER;
  175.   eventPoint:                  Point;
  176.   wRect,screenRect,dragRect:   Rect;
  177.   winSizeLimits:               Rect;
  178.   oldSize:                     Rect;
  179.   newSize,dontCare:            LONGINT;
  180.   envError:                    OSErr;
  181.   cursorRgn:                   RgnHandle;
  182.   hScroll,vScroll:             ControlHandle;
  183.   whichControl:                ControlHandle;
  184.   myWindow,whichWindow:        WindowPtr;
  185.   fatBitsWindow:               WindowPtr;
  186.   HCrefresh:                   Str31;
  187.   wT,wL,wB,wR,wTitle:          Str255;
  188.   toolStr,patStr,msgStr:       Str255;
  189.   widthStr,heightStr:          Str255;
  190.   myBits:                      BitMap;
  191.   theEnv:                      SysEnvRec;
  192.   myEvent:                     EventRecord;
  193.   wRecord:                     WindowRecord;
  194.   HCPort:                      GrafPtr;
  195.   theOffScrHandle:             OffScrHandle;
  196.   theScrollHandle:             ScrollHandle;
  197.   myOffScr:                    OffScrRecord;
  198.   myScrollRecord:              ScrollRecord;
  199.         
  200.     
  201.   FUNCTION TrapAvailable(tNumber: INTEGER; tType:
  202.                            TrapType):BOOLEAN;
  203.  
  204.   {Check to see if a given trap is implemented.}
  205.  
  206.   BEGIN
  207.     TrapAvailable := NGetTrapAddress(tNumber, tType) <> 
  208.                      GetTrapAddress(_Unimplemented);
  209.   END; {TrapAvailable}
  210.  
  211.  
  212.   FUNCTION CreateHScrollBar(theWindow:WindowPtr;
  213.                            theValue,theMin,theMax:INTEGER;
  214.                            theRefCon:LONGINT):ControlHandle;
  215.  
  216.   {Allocate and draw a horizontal scroll bar in theWindow.
  217.    Return a controlHandle to the scroll bar.}
  218.  
  219.   VAR
  220.     myWindowRect,hScrRect:  Rect;
  221.  
  222.   BEGIN
  223.     SetPort(theWindow);
  224.     myWindowRect := theWindow^.portRect;
  225.     SetRect(hScrRect,myWindowRect.left -1,
  226.                      myWindowRect.bottom - 15,
  227.                      myWindowRect.right - 14,
  228.                      myWindowRect.bottom + 1);
  229.     CreateHScrollBar := NewControl(theWindow,hScrRect,
  230.                                    'MyHoriz',TRUE,
  231.                                    theValue,theMin,theMax,
  232.                                    scrollBarProc,theRefCon);
  233.   END; {CreateHScrollBar}
  234.  
  235.  
  236.   FUNCTION CreateVScrollBar(theWindow:WindowPtr;
  237.                            theValue,theMin,theMax:INTEGER;
  238.                            theRefCon:LONGINT):ControlHandle;
  239.  
  240.   {Allocate and draw a vertical scroll bar in theWindow.
  241.    Return a controlHandle to the scroll bar.}
  242.  
  243.   VAR
  244.     myWindowRect,vScrRect:  Rect;
  245.  
  246.   BEGIN
  247.     SetPort(theWindow);
  248.     myWindowRect := theWindow^.portRect;
  249.     SetRect(vScrRect,myWindowRect.right -15,
  250.                      myWindowRect.top - 1,
  251.                      myWindowRect.right + 1,
  252.                      myWindowRect.bottom - 14);
  253.     CreateVScrollBar := NewControl(theWindow,vScrRect,
  254.                                    'MyVert',TRUE,
  255.                                    theValue,theMin,theMax,
  256.                                    scrollBarProc,theRefCon);
  257.   END; {CreateVScrollBar}
  258.     
  259.     
  260.   PROCEDURE InvalScroll(theWindow:WindowPtr);
  261.  
  262.   {Accumulate the rectangles occupied by theWindow's
  263.    horizontal and vertical scroll bars into the update
  264.    region.}
  265.  
  266.   VAR
  267.     theRect,tallRect,wideRect:  Rect;
  268.  
  269.   BEGIN
  270.     SetPort(theWindow);
  271.     theRect := theWindow^.portRect;
  272.     ClipRect(theRect);
  273.  
  274.     {Accumulate tallRect, which is occupied by the vertical
  275.      scroll bar }
  276.  
  277.     SetRect(tallRect,theRect.right-15,
  278.                      theRect.top,
  279.                      theRect.right,
  280.                      theRect.bottom);
  281.     EraseRect(tallRect);
  282.     InvalRect(tallRect);
  283.  
  284.     {Accumulate wideRect, which is occupied by the 
  285.      horizontal scroll bar }
  286.  
  287.     SetRect(wideRect,theRect.left,
  288.                      theRect.bottom-15,
  289.                      theRect.right,
  290.                      theRect.bottom);
  291.     EraseRect(wideRect);
  292.     InvalRect(wideRect);
  293.   END; {InvalScroll}
  294.  
  295.  
  296.   PROCEDURE Deactivate(theWindow:WindowPtr);
  297.  
  298.   {Deactivate the scroll bars in theWindow in accordance
  299.    with the human interface guidelines. This means we
  300.    must erase everything enclosed by the control rec-
  301.    tangles.}
  302.  
  303.   VAR
  304.     theControl:      ControlHandle;
  305.     theControlRect:  Rect;
  306.  
  307.   BEGIN
  308.     {I always title my scroll bars 'MyVert' and 'MyHoriz'
  309.      so I can easily find them by walking a window's
  310.      control list.}
  311.  
  312.     theControl := WindowPeek(theWindow)^.controlList;
  313.     WHILE (theControl <> NIL) DO
  314.     BEGIN
  315.       IF (theControl^^.contrlTitle = 'MyVert') OR
  316.          (theControl^^.contrlTitle = 'MyHoriz') THEN
  317.       BEGIN
  318.         theControlRect := theControl^^.contrlRect;
  319.         InsetRect(theControlRect,1,1);
  320.         EraseRect(theControlRect);
  321.       END; {IF}
  322.       theControl := theControl^^.nextControl;
  323.     END; {WHILE}
  324.   END; {Deactivate}
  325.  
  326.  
  327.   PROCEDURE HiliteScrollBars(theWindow:WindowPtr);
  328.  
  329.   BEGIN
  330.  
  331.     {Reactivate the scroll bars; e.g., when we resume
  332.      under MultiFinder. More next month!}
  333.  
  334.     HiliteControl(vScroll,INTEGER(active));
  335.     HiliteControl(hScroll,INTEGER(active));
  336.   END; {HiliteScrollBars}
  337.  
  338.  
  339.   PROCEDURE MoveScrollBars(theWindow:WindowPtr);
  340.  
  341.   {Call this procedure after theWindow has changed size.
  342.    MoveScrollBars erases theWindow's scroll bars, resizes
  343.    them, and redraws them.}
  344.  
  345.   VAR
  346.     myWindowRect:       Rect;
  347.     vScrRect,hScrRect:  Rect;
  348.  
  349.   BEGIN
  350.     myWindowRect := theWindow^.portRect;
  351.     SetRect(hScrRect,myWindowRect.left - 1,
  352.                      myWindowRect.bottom - 15,
  353.                      myWindowRect.right - 14,
  354.                      myWindowRect.bottom + 1);
  355.     SetRect(vScrRect,myWindowRect.right - 15,
  356.                      myWindowRect.top - 1,
  357.                      myWindowRect.right + 1,
  358.                      myWindowRect.bottom - 14);
  359.     SetPort(theWindow);
  360.     ClipRect(myWindowRect);
  361.  
  362.     {Hide and resize the scroll bars to fit the new window 
  363.      size.}
  364.  
  365.     HideControl(hScroll);
  366.     HideControl(vScroll);
  367.  
  368.     MoveControl(hScroll,hScrRect.left,hScrRect.top);
  369.     SizeControl(hScroll,(hScrRect.right - hScrRect.left),
  370.                         (hScrRect.bottom - hScrRect.top));
  371.  
  372.     MoveControl(vScroll,vScrRect.left,vScrRect.top);
  373.     SizeControl(vScroll,(vScrRect.right - vScrRect.left),
  374.                         (vScrRect.bottom - vScrRect.top));
  375.     HiliteScrollBars(theWindow);
  376.     ShowControl(hScroll);
  377.     ShowControl(vScroll);
  378.   END; {MoveScrollBars}
  379.     
  380.     
  381.   PROCEDURE ScrollWithThumb(theControl:ControlHandle;
  382.                             theEventPoint:Point);
  383.  
  384.   BEGIN
  385.     {Next month!}
  386.   END; {ScrollWithThumb}
  387.  
  388.  
  389.   FUNCTION WhichDevice(thePoint:Point):GDHandle;
  390.  
  391.   {For machines that support color QuickDraw and
  392.    multiple screens, WhichDevice figures out which screen 
  393.    thePoint is on and returns a GDHandle to that screen. 
  394.    thePoint might be where the mouse was clicked, for 
  395.    example. Thanks to Greg Marriott for this code.}
  396.  
  397.   VAR
  398.     aDevice:   GDHandle;
  399.     foundOne:  BOOLEAN;
  400.  
  401.   BEGIN
  402.     aDevice := GetDeviceList;
  403.     foundOne := FALSE;
  404.  
  405.     {Walk the device list until thePoint is contained
  406.      in some device's screen rectangle.}
  407.  
  408.     WHILE (aDevice <> NIL) AND NOT foundOne DO
  409.     BEGIN
  410.       IF PtInRect(thePoint,aDevice^^.gdRect) THEN
  411.       BEGIN
  412.         WhichDevice := aDevice;
  413.         foundOne := TRUE;
  414.       END;
  415.       aDevice := aDevice^^.gdNextGD;
  416.     END;
  417.   END; {WhichDevice}
  418.  
  419.  
  420.   FUNCTION MenuBarHeight: INTEGER;
  421.  
  422.   {Returns the height of the menubar in pixels, as read
  423.    from the low memory global mBarHeight.}
  424.  
  425.   CONST
  426.     mBarHeight = $BAA;
  427.  
  428.   VAR
  429.     menuBarHeightPtr:  ^INTEGER;
  430.  
  431.   BEGIN
  432.     menuBarHeightPtr := Pointer(mBarHeight);
  433.     MenuBarHeight := menuBarHeightPtr^;
  434.   END; {MenuBarHeight}
  435.  
  436.  
  437.   FUNCTION OnAScreen(theRect:Rect):BOOLEAN;
  438.  
  439.   {OnAScreen returns FALSE if all of a window's title
  440.    bar is off the screen or if any part of it is under
  441.    the menubar. The portRect of the window to be checked
  442.    should be passed in theRect.}
  443.  
  444.   CONST
  445.     titleBarHeight  =  18;
  446.  
  447.   VAR
  448.     deskRgn:           RgnHandle;
  449.     topLeft,topRight:  Point;
  450.  
  451.   BEGIN
  452.     deskRgn := GetGrayRgn;
  453.     topLeft.v := theRect.top - titleBarHeight;
  454.     topLeft.h := theRect.left + titleBarHeight;
  455.     topRight.v := topLeft.v;
  456.     topRight.h := theRect.right - titleBarHeight;
  457.     IF ((PtInRgn(topLeft,deskRgn)) OR 
  458.     (PtInRgn(topRight,deskRgn))) THEN
  459.       OnAScreen := TRUE
  460.     ELSE
  461.       OnAScreen := FALSE;
  462.   END; {OnAScreen}
  463.  
  464.  
  465.   PROCEDURE ZoomIt(theWindow:WindowPtr;partCode:INTEGER;
  466.                    clickedWhere:Point);
  467.  
  468.   {ZoomIt supports more elegant window zooming on multiple
  469.    screen systems. theWindow will zoom to fill whatever
  470.    screen the zoom box was on when it was clicked. The
  471.    window state toggles between original size and zoomed
  472.    size, as usual. Thanks to Greg Marriott for this code.}
  473.  
  474.   CONST
  475.     titleBarHeight  =  18;
  476.  
  477.   TYPE
  478.     WStatePtr     =  ^WStateData;
  479.     WStateHandle  =  ^WStatePtr;
  480.  
  481.   VAR
  482.     oldRect,newRect:  Rect;
  483.     maxHeight:        INTEGER;
  484.  
  485.   BEGIN
  486.     oldRect := theWindow^.portRect;
  487.     IF theEnv.hasColorQD THEN
  488.     BEGIN
  489.       newRect := WhichDevice(clickedWhere)^^.gdRect;
  490.       IF WhichDevice(clickedWhere) = GetMainDevice THEN
  491.         newRect.top := newRect.top + MenuBarHeight;
  492.     END
  493.       newRect := GetGrayRgn^^.rgnBBox;
  494.     newRect.left := newRect.left + 2;
  495.     newRect.top := newRect.top + titleBarHeight + 2;
  496.     newRect.right := newRect.right - 3;
  497.     newRect.bottom := newRect.bottom - 3;
  498.     IF NOT EqualRect(oldRect,newRect) THEN
  499.       WITH WindowPeek(theWindow)^ DO
  500.         WStateHandle(dataHandle)^^.stdState := newRect;
  501.     SetPort(theWindow);
  502.     EraseRect(whichWindow^.portRect);        
  503.     InvalRect(whichWindow^.portRect);
  504.     ZoomWindow(theWindow,partcode,FALSE);
  505.   END; {ZoomIt}
  506.  
  507.  
  508.   {$I XCmdGlue.inc}
  509.  
  510.  
  511.   PROCEDURE Fail(errStr:Str255);
  512.  
  513.   {Fail returns errStr to HyperCard and exits the XCMD.
  514.    errStr can then be checked by inspecting HyperCard's
  515.    global variable "the result." See "XCMD's for Hyper-
  516.    Card" by Gary Bond (MIS Press, 1988) for more details.
  517.  
  518.    © 1988 by Gary Bond
  519.    All rights reserved.
  520.    You may use this code for NON-COMMERCIAL purposes.}
  521.  
  522.   BEGIN
  523.     paramPtr^.returnValue := PasToZero(errStr);
  524.     SysBeep(1);
  525.     EXIT(Window);
  526.   END; {Fail}
  527.  
  528.  
  529.   PROCEDURE CheckParamCount;
  530.  
  531.   {CheckParamCount sees if the number of parameters
  532.    passed to the XCMD matches the number expected. If
  533.    not, we exit from the XCMD with an error message.
  534.    See "XCMD's for HyperCard" by Gary Bond (MIS Press,
  535.    1988) for more details.
  536.  
  537.    © 1988 by Gary Bond
  538.    All rights reserved.
  539.    You may use this code for NON-COMMERCIAL purposes.}
  540.  
  541.   VAR
  542.     numParams:  INTEGER;
  543.  
  544.   BEGIN
  545.     numParams := paramPtr^.paramCount;
  546.     IF(numParams <> minParamCount) THEN
  547.       Fail('Form: HyperWindow "Window 
  548.            Title",top,left,bottom,right');
  549.   END;    {CheckParamCount}
  550.  
  551.  
  552.   FUNCTION GetHCVersion: Str255;
  553.  
  554.   {Return a string containing the version of HyperCard
  555.    being used; e.g., '1.2'}
  556.  
  557.   BEGIN
  558.     ZeroToPas(EvalExpr('the version')^,GetHCVersion);
  559.   END; {GetHCVersion}
  560.  
  561.  
  562.   PROCEDURE HideWindoids;
  563.  
  564.   {Get and save the visible state of the tool, pattern,
  565.    message and fatbits windoids; then hide them if they
  566.    are showing.}
  567.  
  568.   VAR
  569.     toolH,patH,msgH,fatH:  Handle;
  570.         
  571.     PROCEDURE HideFatBits;
  572.  
  573.     {HyperCard does not have a built-in command for hiding
  574.      and showing the fatbits windoid, so we have to do it
  575.      ourselves. HideFatBits walks the window list until it
  576.      finds a window with title "FatBits," then hides it if
  577.      the visible field of its WindowRecord is true. 
  578.      HideFatBits also saves the WindowPtr to the fatbits
  579.      windoid so we can use it later (e.g., to show the
  580.      windoid again).}
  581.  
  582.     CONST
  583.       windowList  =  $9D6; {Low memory global location.}
  584.  
  585.     VAR
  586.       theWindow:     WindowPeek;
  587.       theWindowPtr:  ^WindowPtr;
  588.  
  589.     BEGIN
  590.       theWindowPtr := Pointer(windowList);
  591.       theWindow := WindowPeek(theWindowPtr^);
  592.       fatVis := FALSE;
  593.       WHILE (theWindow <> NIL) DO
  594.       BEGIN
  595.         IF (theWindow^.titleHandle^^ = 'FatBits') THEN
  596.         BEGIN
  597.           fatBitsWindow := WindowPtr(theWindow);
  598.           IF (theWindow^.visible = TRUE) THEN
  599.           BEGIN
  600.             fatVis := TRUE;
  601.             HideWindow(fatBitsWindow);
  602.             theWindow := NIL;
  603.           END;
  604.         END;
  605.         IF (theWindow <> NIL) THEN
  606.           theWindow := WindowPeek(theWindow)^.nextWindow;
  607.       END; {WHILE}
  608.     END; {HideFatBits}
  609.  
  610.   BEGIN {HideWindoids}
  611.  
  612.     {Get visible state of windoids.}
  613.  
  614.     toolH := EvalExpr('visible of tool window');
  615.     ZeroToPas(toolH^,toolStr);
  616.     DisposHandle(toolH);
  617.     toolVis := StrToBool(toolStr);
  618.  
  619.     patH := EvalExpr('visible of pattern window');
  620.     ZeroToPas(patH^,patStr);
  621.     DisposHandle(patH);
  622.     patVis := StrToBool(patStr);
  623.  
  624.     msgH := EvalExpr('visible of message window');
  625.     ZeroToPas(msgH^,msgStr);
  626.     DisposHandle(msgH);
  627.     msgVis := StrToBool(msgStr);
  628.  
  629.     {Hide the ones that are showing.}
  630.         
  631.     HideFatBits;
  632.         
  633.     IF toolVis THEN
  634.       SendHCMessage('hide tool window');
  635.     IF patVis THEN
  636.       SendHCMessage('hide pattern window');
  637.     IF msgVis THEN
  638.       SendHCMessage('hide message window');
  639.   END; {HideWindoids}
  640.  
  641.  
  642.   PROCEDURE ShowWindoids;
  643.  
  644.   {This routine assumes HideWindoids has been called
  645.    before. ShowWindoids restores the visible state of
  646.    the windoids to that saved by HideWindoids.}
  647.  
  648.   BEGIN
  649.     IF toolVis THEN
  650.       SendHCMessage('show tool window');
  651.     IF patVis THEN
  652.       SendHCMessage('show pattern window');
  653.     IF msgVis THEN
  654.       SendHCMessage('show message window');
  655.  
  656.     {As in HideWindoids, we must take care of the FatBits
  657.      windoid ourselves.}
  658.  
  659.     IF fatVis THEN
  660.     BEGIN
  661.       ShowWindow(fatBitsWindow);
  662.       SelectWindow(fatBitsWindow);
  663.     END;
  664.   END; {ShowWindoids}
  665.  
  666.  
  667.   PROCEDURE ToggleMenuBar;
  668.  
  669.   {Set the visible of the menubar to not the visible of
  670.    the menubar.}
  671.  
  672.   BEGIN
  673.     IF MenuBarHeight = 0 THEN
  674.       SendHCMessage('show menubar')
  675.     ELSE
  676.       SendHCMessage('hide menubar');
  677.   END; {ToggleMenuBar}
  678.  
  679.  
  680.   PROCEDURE GetHCBitMap;
  681.     
  682.   BEGIN
  683.     {Next month!}
  684.   END; {GetHCBitMap}
  685.  
  686.  
  687.   PROCEDURE AdjustCursor;
  688.  
  689.   {AdjustCursor changes cursorRgn to the region that 
  690.    contains the cursor.  As soon as the cursor moves out of 
  691.    cursorRgn, we get an event and can change the cursor and 
  692.    cursorRgn again. cursorRgn is either the content region 
  693.    of our window or the region containing everything BUT the 
  694.    content region of our window.}
  695.  
  696.   VAR
  697.     mousePt:        Point;
  698.     myWinContRect:  Rect;
  699.     myWinContRgn:   RgnHandle;
  700.     deskRgn:        RgnHandle;
  701.     handHdl:        CursHandle;
  702.  
  703.   BEGIN
  704.     SetPort(myWindow);
  705.     GetMouse(mousePt);
  706.     LocalToGlobal(mousePt);
  707.     myWinContRgn := NewRgn;
  708.  
  709.     {Calculate the "work region" of our window, which is its
  710.      content region minus the scroll bars and grow icon. 
  711.      This is the region within which we want the cursor to 
  712.      change to HyperCard's browse tool, and outside of which 
  713.      we want it to be an arrow.}
  714.  
  715.     WITH WindowPeek(myWindow)^.contRgn^^.rgnBBox DO
  716.       SetRect(myWinContRect,left, 
  717.                             top, 
  718.                             right - 15,
  719.                             bottom - 15);
  720.     RectRgn(myWinContRgn,myWinContRect);
  721.  
  722.     IF PtInRect(mousePt,myWinContRect) THEN
  723.     BEGIN
  724.  
  725.       {The cursor is in the work region of our window. Set
  726.        to browse tool.}
  727.  
  728.       handHdl := GetCursor(browseTool);
  729.       IF (handHdl <> NIL) THEN
  730.         SetCursor(handHdl^^)
  731.       ELSE
  732.  
  733.         {Set to arrow if can't find browse tool resource.}
  734.  
  735.         InitCursor;
  736.  
  737.       {Set the cursor region equal to our window's work 
  738.        region.}
  739.  
  740.       SetEmptyRgn(cursorRgn);
  741.       CopyRgn(myWinContRgn,cursorRgn);
  742.     END
  743.     ELSE
  744.     BEGIN
  745.  
  746.       {The cursor is outside our window. Set to arrow.}
  747.  
  748.       InitCursor;
  749.  
  750.       {Get the current desktop region.}
  751.  
  752.       deskRgn := GetGrayRgn;
  753.  
  754.       {Set cursorRgn to the desktop region's bounding box.  
  755.        It is important to add the menu bar area to cursorRgn 
  756.        too.}
  757.  
  758.       SetRectRgn(cursorRgn, deskRgn^^.rgnBBox.left,
  759.                             deskRgn^^.rgnBBox.top,
  760.                             deskRgn^^.rgnBBox.right,
  761.                             deskRgn^^.rgnBBox.bottom);
  762.                                   
  763.       {Punch out our window's content region from the big 
  764.        region.}
  765.  
  766.       DiffRgn(cursorRgn,myWinContRgn,cursorRgn);
  767.     END;
  768.     DisposeRgn(myWinContRgn);
  769.   END; {AdjustCursor}
  770.  
  771.  
  772. BEGIN {Main Program}
  773.  
  774.   {Check the HyperCard version. Must be 1.2 or greater.}
  775.  
  776.   IF GetHCVersion < '1.2' THEN
  777.     Fail('Sorry, must have HyperCard 1.2 or greater.');
  778.  
  779.   {Save thy grafPort upon entering!}
  780.  
  781.   GetPort(HCPort);
  782.  
  783.   {Check and reset our environment.}
  784.  
  785.   CheckParamCount;
  786.   FlushEvents(everyEvent,0);
  787.   InitCursor;
  788.  
  789.   {Find out what kind of machine we're running on.}
  790.  
  791.   envError := SysEnvirons(1,theEnv);
  792.   IF (envError <> noErr) THEN
  793.     Fail('SysEnvirons call failed.');
  794.  
  795.   {Convert HyperTalk input parameters for use here.}
  796.  
  797.   ZeroToPas(paramPtr^.params[1]^,wTitle);
  798.   ZeroToPas(paramPtr^.params[2]^,wT);
  799.   ZeroToPas(paramPtr^.params[3]^,wL);
  800.   ZeroToPas(paramPtr^.params[4]^,wB);
  801.   ZeroToPas(paramPtr^.params[5]^,wR);
  802.  
  803.   wTop := INTEGER(StrToNum(wT));
  804.   wLeft := INTEGER(StrToNum(wL));
  805.   wBottom := INTEGER(StrToNum(wB));
  806.   wRight := INTEGER(StrToNum(wR));
  807.  
  808.   {If window size parameters are too small or illegal, set
  809.    the window to a predefined minimum size.}
  810.  
  811.   IF ((wRight - wLeft) < smallestWidth) THEN
  812.     wRight := wLeft + smallestWidth;
  813.   IF ((wBottom - wTop) < smallestHeight) THEN
  814.     wBottom := wTop + smallestHeight;
  815.  
  816.   {Make sure the user is not trying to draw the window off
  817.    the screen or under the menubar.}
  818.  
  819.   SetRect(wRect,wLeft,wTop,wRight,wBottom);
  820.   IF NOT OnAScreen(wRect) THEN
  821.     Fail('You are trying to draw your window off the 
  822.          screen!');
  823.  
  824.   {Get the bounds of the desktop.}
  825.  
  826.   screenRect := GetGrayRgn^^.rgnBBox;
  827.  
  828.   {If we have a small screen, make a note of it so we can
  829.    hide the card window during context switches under
  830.    MultiFinder.}
  831.  
  832.   ZeroToPas(EvalExpr('item 3 of the screenRect')^,widthStr);
  833.   screenWidth := INTEGER(StrToNum(widthStr));
  834.   ZeroToPas(EvalExpr('item 4 of the screenRect')^,
  835.             heightStr);
  836.   screenHeight := INTEGER(StrToNum(heightStr));
  837.  
  838.   IF (screenWidth = 512) AND (screenHeight = 342) THEN
  839.     smallScreen := TRUE
  840.   ELSE
  841.     smallScreen := FALSE;
  842.  
  843.   HideWindoids;
  844.  
  845.   IF MenuBarHeight > 0 THEN
  846.     menuWasHidden := FALSE
  847.   ELSE
  848.     menuWasHidden := TRUE;
  849.  
  850.   {This is for scrolling and will be explained next month.}
  851.  
  852.   theOffScrHandle := OffScrHandle(NewHandle
  853.                      (SizeOf(OffScrRecord)));
  854.   IF MemError <> noErr THEN
  855.     Fail('Out of memory.  Buy more.');
  856.  
  857.   myDocWidth := HCWidth + padding;
  858.   myDocHeight := HCHeight + padding;
  859.  
  860.   WITH theOffScrHandle^^ DO
  861.   BEGIN
  862.     {Next month!}
  863.   END;
  864.  
  865.   GetHCBitMap;
  866.  
  867.   {Draw the window!}
  868.  
  869.   myWindow := NewWindow(@wRecord,wRect,
  870.                         wTitle,TRUE,zoomDocProc,
  871.                         WindowPtr(-1),TRUE,1);
  872.   IF (myWindow = NIL) THEN
  873.   BEGIN
  874.     ShowWindoids;
  875.     Fail('Not enough memory to draw window.');
  876.   END
  877.   ELSE
  878.   BEGIN
  879.  
  880.     {This is for scrolling. Stay tuned....}
  881.  
  882.     SetWRefCon(myWindow,LONGINT(theOffScrHandle));
  883.     InitBlit(myWindow);
  884.     DrawGrowIcon(myWindow);
  885.     theScrollHandle := ScrollHandle(NewHandle
  886.                        (SizeOf(ScrollRecord)));
  887.     IF MemError <> noErr THEN
  888.       Fail('Out of memory.  Buy more.');
  889.  
  890.     {Draw horizontal and vertical scroll bars in our 
  891.      window.}
  892.  
  893.     hScroll := CreateHScrollBar(myWindow,0,0,
  894.                                 myDocWidth,
  895.                                 LONGINT(theScrollHandle));
  896.     vScroll := CreateVScrollBar(myWindow,0,0,
  897.                                 myDocHeight,
  898.                                 LONGINT(theScrollHandle));
  899.     HiliteScrollBars(myWindow);
  900.     DrawContents(myWindow);
  901.     SetRect(dragRect,screenRect.left + 4,
  902.                      screenRect.top,
  903.                      screenRect.right - 4,
  904.                      screenRect.bottom - 4);
  905.     largestHeight := screenRect.bottom - screenRect.top;
  906.     largestWidth := screenRect.right - screenRect.left;
  907.     SetRect(winSizeLimits,smallestWidth,
  908.                           smallestHeight,
  909.                           largestWidth,
  910.                           largestHeight);
  911.             
  912.     HCRefresh := 'Go to this card';
  913.     cursorRgn := NewRgn;
  914.     inBackGround := FALSE;
  915.     DoneFlag := FALSE;
  916.     REPEAT
  917.  
  918.       {Call WaitNextEvent, if available. Otherwise call
  919.        GetNextEvent.}
  920.  
  921.       IF hasWaitNextEvent THEN
  922.         HaveEvent := WaitNextEvent(everyEvent,
  923.                                    myEvent,30,cursorRgn)
  924.       ELSE
  925.       BEGIN
  926.         HaveEvent := GetNextEvent(everyEvent,myEvent);
  927.         AdjustCursor;
  928.       END;
  929.       IF HaveEvent THEN
  930.       BEGIN
  931.         IF (myEvent.what = app4Evt) THEN
  932.  
  933.           {Pre-process app4Evt's fed to us by MultiFinder.}
  934.  
  935.           CASE BSR(myEvent.message,24) OF
  936.  
  937.             MouseMovedEvt:
  938.               AdjustCursor;
  939.  
  940.             SuspendResumeEvt:
  941.             BEGIN
  942.            myEvent.what := activateEvt;
  943.  
  944.               {Resume event.}
  945.  
  946.               IF (BAND(myEvent.message,SuspendEventMask) <> 
  947.               0) THEN
  948.                 inBackground := FALSE
  949.               ELSE
  950.  
  951.                 {Suspend event.}
  952.  
  953.                 inBackground := TRUE;
  954.  
  955.               myEvent.message := LONGINT(myWindow);
  956.             END; {SuspendResumeEvt}
  957.  
  958.           END; {CASE BSR}
  959.       END; {IF HaveEvent}
  960.  
  961.       CASE myEvent.what OF
  962.  
  963.         mouseDown:
  964.         BEGIN
  965.           partCode := FindWindow(myEvent.where,whichWindow);
  966.           IF (whichWindow = myWindow) THEN
  967.           BEGIN
  968.  
  969.             {Deal with mouse hits to our window.}
  970.  
  971.             CASE partCode OF
  972.  
  973.               inDrag:
  974.               BEGIN
  975.                 SelectWindow(whichWindow); {DragWindow bug}
  976.                 DragWindow(whichWindow,myEvent.where,
  977.                            dragRect);
  978.                 SendCardMessage(HCrefresh);
  979.                 AdjustCursor;
  980.               END;
  981.  
  982.               inGrow:
  983.                 IF StillDown THEN {GrowWindow bug}
  984.                 BEGIN
  985.                   oldSize := whichWindow^.portRect;
  986.                   newSize := GrowWindow(whichWindow,
  987.                                         myEvent.where,
  988.                                         winSizeLimits);
  989.                   IF (newSize <> 0) THEN
  990.                   BEGIN
  991.                     InvalScroll(whichWindow);
  992.                     SizeWindow(whichWindow,
  993.                                LOWORD(newSize),
  994.                                HIWORD(newSize),FALSE);
  995.                     InvalContents(whichWindow,oldSize);
  996.                     DrawGrowIcon(whichWindow);
  997.                     MoveScrollBars(whichWindow);
  998.                   END; {IF newSize}
  999.                 END; {IF StillDown}
  1000.               END; {inGrow}
  1001.  
  1002.               inZoomIn,inZoomOut:
  1003.               BEGIN
  1004.                 IF (TrackBox(whichWindow,
  1005.                              myEvent.where,
  1006.                              partCode)) THEN
  1007.                 BEGIN
  1008.                   InvalScroll(whichWindow);
  1009.                   ZoomIt(whichWindow,partCode,
  1010.                          myEvent.where);
  1011.                   InvalContents(whichWindow,oldSize);
  1012.                   DrawGrowIcon(whichWindow);
  1013.                   MoveScrollBars(whichWindow);
  1014.                 END; {IF TrackBox}
  1015.               END; {inZoomIn,inZoomOut}
  1016.  
  1017.               inContent:
  1018.               BEGIN
  1019.                 SetPort(whichWindow);
  1020.                 eventPoint := myEvent.where;
  1021.                 GlobalToLocal(eventPoint);
  1022.                 controlCode := FindControl(eventPoint,
  1023.                                            whichWindow,
  1024.                                            whichControl);
  1025.                 ClipRect(whichWindow^.portRect);
  1026.                 IF (controlCode = inThumb) THEN
  1027.                   ScrollWithThumb(whichControl,eventPoint)
  1028.                 ELSE IF (controlCode <> 0) THEN
  1029.                   dummy := TrackControl(whichControl,
  1030.                                         eventPoint,
  1031.                                         @MyScroll);
  1032.               END; {inContent}
  1033.  
  1034.               inGoAway:
  1035.               BEGIN
  1036.                 IF (TrackGoAway(whichWindow,myEvent.where)) 
  1037.                 THEN
  1038.                   DoneFlag := TRUE;
  1039.               END; {inGoAway}
  1040.  
  1041.             END; {CASE partCode}
  1042.           END; {IF whichWindow = myWindow}
  1043.         END; {mouseDown}
  1044.                     
  1045.         activateEvt:
  1046.         BEGIN
  1047.           IF (WindowPtr(myEvent.message) = myWindow) THEN
  1048.           BEGIN
  1049.             SetPort(myWindow);
  1050.             ClipRect(myWindow^.portRect);
  1051.             DrawGrowIcon(myWindow);
  1052.             IF inBackground THEN
  1053.             BEGIN
  1054.  
  1055.               {We've been sent behind another application
  1056.                under MultiFinder, so deactivate the scroll
  1057.                bars and show the menubar if it was hidden.}
  1058.  
  1059.               Deactivate(myWindow);
  1060.               IF smallScreen THEN
  1061.                 ShowHide(WindowPtr(HCPort),FALSE);
  1062.               IF MenuBarHeight = 0 THEN
  1063.             BEGIN
  1064.                 SendHCMessage('show menubar');
  1065.                 menuWasHidden := TRUE;
  1066.               END
  1067.               ELSE
  1068.                 menuWasHidden := FALSE;
  1069.             END
  1070.             ELSE
  1071.             BEGIN
  1072.  
  1073.               {We've been brought to the front under Multi-
  1074.                Finder, so reactivate the scroll bars and
  1075.                hide the menubar if it was hidden before.}
  1076.  
  1077.               ShowHide(WindowPtr(HCPort),TRUE);
  1078.               IF menuWasHidden THEN
  1079.                 SendHCMessage('hide menubar');
  1080.               DrawControls(myWindow);
  1081.               HiliteScrollBars(myWindow);
  1082.               FlushEvents(everyEvent,0);
  1083.             END; {IF inBackground}
  1084.           END; {IF WindowPtr}
  1085.         END; {activateEvt}
  1086.  
  1087.         updateEvt:
  1088.         BEGIN
  1089.  
  1090.           {Handle updates to our window.}
  1091.  
  1092.           IF (WindowPtr(myEvent.message) = myWindow) THEN
  1093.           BEGIN
  1094.  
  1095.             {Always do this stuff}
  1096.  
  1097.             SetPort(myWindow);
  1098.             BeginUpdate(myWindow);
  1099.             ClipRect(myWindow^.portRect);
  1100.             DrawGrowIcon(myWindow);
  1101.  
  1102.             {Always do this stuff under single Finder but
  1103.              only if in foreground under MultiFinder}
  1104.  
  1105.             IF NOT inBackground THEN
  1106.             BEGIN
  1107.               HiliteScrollBars(myWindow);
  1108.               DrawControls(myWindow);
  1109.               AdjustCursor;
  1110.             END;
  1111.  
  1112.             {Always do this stuff}
  1113.  
  1114.             DrawContents(myWindow);
  1115.             EndUpdate(myWindow);
  1116.           END {IF myEvent.message}
  1117.  
  1118.           {Handle updates to HyperCard's card window.}
  1119.  
  1120.           ELSE IF (WindowPtr(myEvent.message) = 
  1121.           WindowPtr(HCPort)) THEN
  1122.           BEGIN
  1123.             SendHCMessage(HCRefresh);
  1124.  
  1125.             {Must zero out card window's update region
  1126.              ourselves because the SendHCMessage call
  1127.              doesn't do it, and we'll wind up in an
  1128.              infinite loop if we don't.}
  1129.  
  1130.             BeginUpdate(WindowPtr(HCPort));
  1131.             EndUpdate(WindowPtr(HCPort));
  1132.           END; {IF... ELSE}
  1133.         END; {updateEvt}
  1134.  
  1135.         keyDown:
  1136.         BEGIN
  1137.           IF (BitAnd(myEvent.modifiers,cmdKey) <> 0) THEN
  1138.           BEGIN
  1139.             charCode := BitAnd(myEvent.message,
  1140.                                charCodeMask);
  1141.  
  1142.             {Pressing command-spacebar toggles the menubar.}
  1143.  
  1144.             IF (CHR(charCode) = ' ') THEN
  1145.               ToggleMenuBar;
  1146.  
  1147.             {Pressing command-W closes the window and exits
  1148.              the XCMD.}
  1149.  
  1150.             IF (CHR(charCode) = 'w') THEN
  1151.               DoneFlag := True;
  1152.           END;
  1153.         END;
  1154.       END; {CASE myEvent.what}
  1155.  
  1156.     UNTIL (DoneFlag = True);
  1157.  
  1158.     {Clean up and get outta here!}
  1159.  
  1160.     DisposeRgn(cursorRgn);
  1161.     DisposHandle(Handle(theOffScrHandle));
  1162.     DisposHandle(Handle(theScrollHandle));
  1163.     CloseWindow(myWindow);
  1164.     SendCardMessage(HCrefresh);
  1165.     ShowWindoids;
  1166.     InitCursor;
  1167.     FlushEvents(everyEvent,0);
  1168.  
  1169.     {Restore thy grafPort}
  1170.  
  1171.     SetPort(HCPort);
  1172.   END; {IF myWindow...ELSE}
  1173. END; {Main}
  1174. END. {Window}
  1175.